package org.study.shardingsphere.boot.algorithm;

import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Range;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.standard.*;
import org.study.shardingsphere.boot.util.DateUtils;

import java.util.*;

/**
 * 自定义 Standard 分表策略。
 * 参考 https://blog.csdn.net/weixin_44211703/article/details/122684779
 *
 * @author Administrator
 * @date 2022-03-09
 */
@Slf4j
public class StandardShardingAlgorithm4TableDemo1 implements StandardShardingAlgorithm<String> {
    private final int MOD = 5;

    /**
     * 方法功能描述
     *
     * @param tableNames           配置文件中定义的表名称集合
     * @param preciseShardingValue 执行 insert、select、update、delete 操作时，create_time 字段的值
     * @return java.lang.String shardingValue 年份对应的表名。比如 1995 =3，返回表名 t_test_1995
     */
    @Override
    public String doSharding(Collection<String> tableNames, PreciseShardingValue<String> preciseShardingValue) {
        log.info("tableNames：{}，preciseShardingValue：{}", JSON.toJSONString(tableNames), JSON.toJSONString(preciseShardingValue));
        // 获取传递的字段值
        String shardingValue = preciseShardingValue.getValue();
        if (shardingValue == null) {
            throw new UnsupportedOperationException("分片键 " + preciseShardingValue.getColumnName() + " 的值不能为空");
        }
        // 获取年份
        int year = DateUtils.getYearFromString(shardingValue);
        // 根据年份判断表名集合是否存在对应表表名集合，存在时返回表名
        for (String each : tableNames) {
            if (each.endsWith(String.valueOf(year))) {
                return each;
            }
        }
        throw new UnsupportedOperationException("没有匹配到可用的数据库.表节点");
    }

    /**
     * 方法功能描述
     *
     * @param tableNames         配置文件中定义的表名称集合
     * @param rangeShardingValue 执行 insert、select、update、delete 操作时，create_time 范围查询字段值。比如 between 2015-01-01 and 2021-01-01，存储的就是 2015-01-01 和 2021-01-01
     * @return java.util.Collection<java.lang.String> rangeShardingValue 年份对应的表名集合。比如 between 2020-01-01 and 2021-01-01，根据这时间段年份，得到返回的集合是 t_test_2020,t_test_2021
     */
    @Override
    public Collection<String> doSharding(Collection<String> tableNames, RangeShardingValue<String> rangeShardingValue) {
        log.info("tableNames：{}，rangeShardingValue：{}", JSON.toJSONString(tableNames), JSON.toJSONString(rangeShardingValue));
        Collection<String> result = new LinkedHashSet<>();
        // 获得范围区间值
        Range<String> valueRange = rangeShardingValue.getValueRange();
        // 分別获得范围区间值上、下限
        String upperEndpoint = valueRange.hasUpperBound() ? valueRange.upperEndpoint() : "";
        String lowerEndpoint = valueRange.hasLowerBound() ? valueRange.lowerEndpoint() : "";
        // 分別获得上、下限年份
        int upperYear = DateUtils.getYearFromString(upperEndpoint);
        int lowerYear = DateUtils.getYearFromString(lowerEndpoint);
        if (lowerYear == -1 && upperYear != -1) {
            // 下限年份为空时，上限不为空时，下限=上限-5
            lowerYear = upperYear - MOD;
        } else if (lowerYear != -1 && upperYear == -1) {
            // 下限不为空，上限为空，上限=下限+5
            upperYear = lowerYear + MOD;
        }
        // 根据上下限范围，循环取值判断对应的表名称，返回符合条件的表名称集合
        for (int i = lowerYear; i <= upperYear; i++) {
            for (String each : tableNames) {
                if (each.endsWith(String.valueOf(i))) {
                    result.add(each);
                }
            }
        }
        return result;
    }

    @Override
    public String getType() {
        return "SHARDING_TABLE_DATE1";
    }

    @Override
    public void init(Properties props) {

    }
}